package org.dyndns.opendemogroup.optimizer;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * A class to test the class Xml
 */
public class XmlTest
{

	private Document doc;

	@Before
	public void loadXml ( )
	{
		doc =
			Xml
					.loadDocument ( ""
							+ "<recipes>"
							+ "<recipe title=\"Blueberry muffins\">"
							+ "<!-- Don't try this at home,"
							+ "I just made this recipe up for testing purposes! -->"
							+ "<ingredients>"
							+ "<ingredient type=\"wet\" name=\"blueberries\" cups=\"1\" />"
							+ "<ingredient type=\"wet\" name=\"milk\" cups=\"0.5\" />"
							+ "<ingredient type=\"wet\" name=\"eggs\" units=\"1\" />"
							+ "<ingredient type=\"dry\" name=\"flour\" cups=\"1\" />"
							+ "<ingredient type=\"dry\" name=\"sugar\" cups=\"0.25\" />"
							+ "<ingredient type=\"dry\" name=\"baking powder\" tableSpoons=\"1\" />"
							+ "</ingredients>"
							+ "<instructions>"
							+ "<instruction type=\"preparation\">Pre-heat oven to 350F</instruction>"
							+ "<instruction type=\"preparation\">Retrieve all the ingredients from their storage</instruction>"
							+ "<instruction type=\"mix\">All the wet ingredients together</instruction>"
							+ "<instruction type=\"mix\">All the dry ingredients together</instruction>"
							+ "<instruction type=\"mix\">The wet ingredients together with the dry ingredients</instruction>"
							+ "<instruction type=\"pour\">Dispense the batter into a muffin pan</instruction>"
							+ "<instruction type=\"bake\">Bake for 30 minutes or until a toothpick does not accumulate batter when pricking muffins</instruction>"
							+ "</instructions>" + "</recipe>"
							+ "<recipe title=\"Strawberry muffins\">"
							+ "<!-- TODO: add content here -->" + "</recipe>"
							+ "</recipes>" );
	}

	/**
	 * Tests the <i>selectSingleNode</i> method with an XPath query that
	 * returns an element which was found directly under the context node.
	 */
	@Test
	public void selectSingleNode_SelectChildElement ( )
	{
		Element rootNode = doc.getDocumentElement ( );
		String expression = "recipe[@title='Strawberry muffins']";
		Node actual = Xml.selectSingleNode ( rootNode, expression );

		assertEquals ( "recipe", actual.getNodeName ( ) );
		assertEquals ( Node.ELEMENT_NODE, actual.getNodeType ( ) );

		final NamedNodeMap attributes = actual.getAttributes ( );
		final Node titleNode = attributes.getNamedItem ( "title" );

		assertEquals ( "title", titleNode.getNodeName ( ) );
		assertEquals ( Node.ATTRIBUTE_NODE, titleNode.getNodeType ( ) );
		assertEquals ( "Strawberry muffins", titleNode.getNodeValue ( ) );
	}

	/**
	 * Tests the <i>selectSingleNode</i> method with an XPath query that
	 * returns an element which was found indirectly under the context node.
	 */
	@Test
	public void selectSingleNode_SelectDescendentElement ( )
	{
		Element rootNode = doc.getDocumentElement ( );
		String expression =
			"recipe[@title='Blueberry muffins']/instructions/instruction[@type='pour']";
		Node actual = Xml.selectSingleNode ( rootNode, expression );

		assertEquals ( "instruction", actual.getNodeName ( ) );
		assertEquals ( Node.ELEMENT_NODE, actual.getNodeType ( ) );

		assertEquals ( "Dispense the batter into a muffin pan", actual
				.getTextContent ( ) );
	}

	/**
	 * Tests the <i>selectNodes</i> method with an XPath query that returns
	 * elements which were found indirectly under the context node.
	 */
	@Test
	public void selectNodes_SelectDescendentElements ( )
	{
		Element rootNode = doc.getDocumentElement ( );
		String expression =
			"recipe[@title='Blueberry muffins']/ingredients/ingredient[@type='dry']";
		NodeList actual = Xml.selectNodes ( rootNode, expression );

		String[] names = new String[]
		{
			"flour", "sugar", "baking powder"
		};
		assertEquals ( names.length, actual.getLength ( ) );
		for ( int i = 0; i < names.length; i++ )
		{
			assertEquals ( names[i], actual.item ( i ).getAttributes ( )
					.getNamedItem ( "name" ).getTextContent ( ) );
		}
	}

}
